# -*- coding: utf-8 -*-

VERSION = '0.10.0'

import os

import gtk

import Plugin

from kidux.apps.im.wrapper import wrappers
from kidux.apps.im.client import IMClient
from kidux.apps.im.config import DEBUG

from AvatarHistory import getLastCachedAvatar
from FileTransfer import FileTransfer
from abstract import status as ModuleStatus
from emesenelib.ContactData import Contact

FORCE_SYSTEM = True

PROCEED = True
STOP = False

class MainClass(Plugin.Plugin):
    description = 'Kidux Parental Control'
    authors = { 'Osvaldo Santana Neto' : 'osvaldo@kidux.net',
                'Tiago Dreyer' : 'tndreyer@uol.com.br'}
    website = "http://www.kidux.net"
    displayName = 'Kidux Parental Control'
    name = "Kidux"
    forceEnabled = True

    def _dbg(self, *args, **kwargs):
        if DEBUG:
            print "DEBUG: plugin:kidux:", args, kwargs

    def __init__(self, controller, msn):
        super(MainClass, self).__init__(controller, msn)
        self.enabled = False
        self.controller = controller
        self.msn = msn
        self.account = self.msn.user
        self.personalIP = self.msn.socket._host
        self.switchboardList = []

        self.client = IMClient(self)

        self.buddyList = controller.contacts.contacts

        self.personalStatusChanged(controller, msn, msn.status)
        self.personalNickChanged(controller.mainWindow.userPanel, msn, None, msn.getNick())
        self.personalMessageChanged(controller.mainWindow.userPanel, msn, self.account, msn.personalMessage)
        self.personalAvatarChanged(controller, controller.avatar.imagePath)

        self.controller.contacts.signal_connect("contact-status-changed", self.contactSetStatus)
        self.controller.contacts.signal_connect("contact-nick-changed", self.contactSetNick)
        self.controller.groups.signal_connect("group-name-changed", self.renameGroup)

        self._loginAlert = False


    def start(self):
        self._dbg("Kidux Parental Control Enabled")
        wrappers.plugin = self
        self.enabled = True

    def stop(self):
        wrappers.plugin = None
        self.enabled = False
        self._dbg("Kidux Parental Control Disabled")

    def check(self):
        self._dbg("Kidux Plugin Check")
        return (True, 'Ok')


    def personalStatusChanged(self, controller, msn, status):
        self._dbg("personalStatusChanged", status)
        if not self.isApplicationAllowed():
            return STOP

        if status == "HDN":
            isOnline = False
        else:
            isOnline = True
        self.client.setStatus(isOnline, self.account)
        return PROCEED

    def personalNickChanged(self, userPanel, msn, oldNick, nick):
        self._dbg("personalNickChanged", nick)
        if not self.isApplicationAllowed():
            return STOP

        self.client.setNick(nick, self.account)
        return PROCEED

    def personalMessageChanged(self, userPanel, msn, accountId, message):
        self._dbg("personalMessageChanged", message)
        if not self.isApplicationAllowed():
            return STOP

        self.client.setMessage(message, self.account)
        return PROCEED

    def personalAvatarChanged(self, controller, imagePath):
        self._dbg("personalAvatarChanged", imagePath)

        if not self.isApplicationAllowed():
            return STOP

        if not imagePath:
            return PROCEED

        self.client.setAvatar(imagePath, self.account)
        return PROCEED

    def disconnect(self, controller, status):
        self._dbg("disconnect")
        self.client.disconnect(self.account)
        return PROCEED

    def isApplicationAllowed(self):
        self._dbg("isApplicationAllowed")
        return self.client.isApplicationAllowed()

    def isContactAllowed(self, contactId):
        self._dbg("isContactAllowed", contactId)
        return self.isApplicationAllowed() and self.client.isContactAllowed(self.account, contactId)

    def isFileTransferAllowed(self, contactId):
        self._dbg("isFileTransferAllowed", contactId)
        return self.isApplicationAllowed() and self.client.isFileTransferAllowed(self.account, contactId)

    def logOutgoingMessage(self, conversationManager, conversation, message):
        self._dbg("logOutgoingMessage", message)
        contacts = conversation.switchboard.members.keys()
        conversationId = conversation.switchboard.authenticationString
        receiver = conversation.switchboard.firstUser

        if not conversationId in self.switchboardList:
            self.switchboardList.append(conversationId)
        self.client.logConversation(conversationId, message, self.account)

        allowed = self.isContactAllowed(receiver)
        if not allowed:
            conversation.appendOutputText(None, 'Message blocked by Kidux Plugin', 'error')
        return allowed

    def logIncomingMessage(self, conversationManager, conversation, sender, senderName, message, format, charset):
        self._dbg("logIncomingMessage", sender, message)
        contacts = conversation.switchboard.members.keys()
        conversationId = conversation.switchboard.authenticationString

        if not conversationId in self.switchboardList:
            self.switchboardList.append(conversationId)
        self.client.logConversation(conversationId, message, self.account, sender)

        return self.isContactAllowed(sender)

    def newConversation(self, conversationManager, msn, contactId, switchboard, weStarted):
        self._dbg("newConversation", conversationManager, msn, contactId, switchboard, weStarted)
        try:
            contacts = switchboard.members.keys()
            return all( (self.isContactAllowed(contact) for contact in contacts) )
        except AttributeError:
            return PROCEED # default policy
        return STOP

    def typingMessage(self, conversation, switchboard, contactId):
        self._dbg("typingMessage", conversation, switchboard, contactId)
        return self.isContactAllowed(contactId)

    def userJoin(self, conversation, switchboard, contactId):
        self._dbg("userJoin", conversation, switchboard, contactId)
        contacts = switchboard.members.keys()
        conversationId = switchboard.authenticationString
        self.client.enterConversation(conversationId, self.account, contactId)
        return PROCEED

    def userLeave(self, conversation, switchboard, contactId):
        members = switchboard.members.keys()
        conversationId = switchboard.authenticationString
        self._dbg("userLeave", members, conversationId, contactId)
        self.client.leaveConversation(conversationId, self.account, contactId)
        return PROCEED

    def addContact(self, contactManager, contactId, group=""):
        self._dbg("addContact", contactManager, contactId, group)
        if not self.isApplicationAllowed():
            return STOP
        self.client.addContact(group, self.account, contactId)
        return PROCEED

    def removeContact(self, contactManager, contactId):
        self._dbg("removeContact", contactManager, contactId)
        if not self.isApplicationAllowed():
            return STOP
        self.client.removeContact(self.account, contactId)
        return PROCEED

    def contactSetStatus(self, contactManager, contact, oldStatus):
        self._dbg("contactSetStatus", contactManager, contact, oldStatus)
        if not self.isApplicationAllowed():
            return STOP
        status = contact.status != ModuleStatus.OFFLINE
        if status:
            self.client.setMessage(contact.message, self.account, contact.account)
        self.client.setStatus(status, self.account, contact.account)
        return PROCEED

    def contactSetNick(self, contactManager, contact, oldNick):
        self._dbg("contactSetNick", contactManager, contact, oldNick)
        if not self.isApplicationAllowed():
            return STOP
        self.client.setNick(contact.nick, self.account, contact.account)
        return PROCEED

    def contactMessageChanged(self, contactManager, contactId, message):
        self._dbg("contactMessageChanged", contactManager, contactId, message)
        if not self.isApplicationAllowed():
            return STOP
        self.client.setMessage(message, self.account, contactId)
        return self.isContactAllowed(contactId)

    def __findContactAvatar(self, contact):
        try:
            contactId = contact.email
            picturePath = contact.displayPicturePath
        except AttributeError:
            contactId = contact.account
            c = Contact(contactId)
            c.msnobj = self.controller.msn.msnobj
            picturePath = c.displayPicturePath

        imagePaths = [
            os.path.join(self.controller.config.getCachePath(), picturePath),
            getLastCachedAvatar(contactId, self.controller.config.getCachePath()),
        ]
        for imagePath in imagePaths:
            if os.path.isfile(imagePath):
                return imagePath

    def contactAvatarChanged(self, userList, contact):
        self._dbg("contactAvatarChanged", userList, contact)
        if contact.email == self.account:
            return PROCEED
        if not self.isApplicationAllowed():
            return STOP
        self.client.setAvatar(self.__findContactAvatar(contact), self.account, contact.email)
        return PROCEED

    def __findLocalPath(self, config, fileName, sender):
        receivedFilesDir = os.path.expanduser(config.user['receivedFilesDir'])

        if not os.path.isdir(receivedFilesDir):
            receivedFilesDir = os.path.expanduser('~/')

        if config.user['receivedFilesSortedByUser']:
            receivedFilesDirSub = os.path.join(receivedFilesDir, sender)
            if os.path.isdir(receivedFilesDirSub):
                receivedFilesDir = receivedFilesDirSub
            else:
                try:
                    os.mkdir(receivedFilesDirSub)
                    receivedFilesDir = receivedFilesDirSub
                except IOError:
                    pass
        name = os.path.join(receivedFilesDir, fileName)

        num = 0
        numstr = ''
        while os.path.exists(name + numstr):
            num += 1
            numstr = '.' + str(num)

        return name + numstr

    def fileReceived(self, fileTransfer, p2pUser, session, context, src, receiver):
        self._dbg("fileReceived", fileTransfer, p2pUser, session, context, src, receiver)

        if not self.isApplicationAllowed():
            return STOP

        sender = p2pUser.mail
        conversationId = fileTransfer.conversation.switchboard.authenticationString
        remoteFileName = context.filename
        localPath = self.__findLocalPath(self.controller.config, remoteFileName, sender)

        if receiver == 'Me':
            self.client.logFileTransfer(conversationId, remoteFileName, localPath, self.account)
        else:
            self.client.logFileTransfer(conversationId, remoteFileName, localPath, self.account, sender)
        return PROCEED

    def fileTransfer(self, conversation, p2pUser, session, context, receiver):
        self._dbg("fileTransfer", conversation, p2pUser, session, context, receiver)

        sender = p2pUser.mail
        allowed = self.isFileTransferAllowed(sender)

        if not allowed:
            # send 'cancel' to sender.
            ft = FileTransfer(self.controller, p2pUser, conversation, session, context, receiver)
            ft.p2p.emit('file-transfer-canceled', ft.session, ft.context, ft.sender)
            ft.state = ft.FAILED
            ft.disconnect()
            conversation.appendOutputText(None, 'The user %s tried to send a file that was blocked by Kidux' % (sender,), 'error')

        return allowed

    def _blockFileSend(self, conversation):
        contacts = conversation.switchboard.members.keys()
        blocked = (not self.isApplicationAllowed()) or [ contact for contact in contacts if not self.isFileTransferAllowed(contact) ]

        if blocked:
            conversation.appendOutputText(None, 'Send file to %s is blocked by Kidux Plugin' % (', '.join(blocked),), 'error')

        return not blocked

    def fileSend(self, toolBar, toolButton):
        self._dbg("fileSend", toolBar, toolButton)
        return self._blockFileSend(toolBar.parentUI.parentConversation)

    def menuFileSend(self, conversationMenu, menuItem):
        self._dbg("menuFileSend", conversationMenu, menuItem)
        return self._blockFileSend(conversationMenu.parentConversationWindow.conversation)

    def contactNewGroup(self, contactManager, contactId, oldName, newName):
        self._dbg("contactNewGroup", contactManager, contactId, oldName, newName)
        if not self.isApplicationAllowed():
            return STOP
        self.client.setGroup(newName, self.account, contactId)
        return PROCEED

    def renameGroup(self, groupManager, group, oldName):
        self._dbg("renameGroup", groupManager, group, oldName)
        if not self.isApplicationAllowed():
            return STOP
        for contact in group.contacts:
            self.client.setGroup(group.name, self.account, contact)
        return PROCEED

    def alert(self, message):
        dialog = gtk.MessageDialog(self.controller.mainWindow, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, message)
        dialog.run()
        dialog.destroy()

    def blockContact(self, userMenu, menuItem):
        self._dbg("blockContact", userMenu, menuItem)
        receiver = userMenu.user._email
        option = menuItem.get_child().get_text()
        if "mail" not in option.lower():
            allowed = self.isContactAllowed(receiver)
        else:
            allowed = self.isFileTransferAllowed(receiver)

        if not allowed:
            self.alert("This user is blocked by Kidux Plugin.")
        return allowed

    def blockInvite(self, conversation, contactId):
        self._dbg("blockInvite", conversation, contactId)

        allowed = self.isContactAllowed(contactId)

        if not allowed:
            self.alert("This user is blocked by Kidux Plugin.")
        return allowed

    def blockLogin(self, controller, msn, status, _, contactInfo):
        self._dbg("blockLogin", controller, msn, status, _, contactInfo)

        if self.isApplicationAllowed():
            return PROCEED

        if self._loginAlert:
            return PROCEED

        self._loginAlert = True
        self.alert("This application is blocked by Kidux Plugin.")
        self.controller.quit(1)
        return PROCEED

